﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections.ObjectModel;
using System.Data.Common;
using CH.Study.ConsoleApp.ExpressionTree;
using System.Data.SqlClient;
using System.Data;

namespace CH.Study.ConsoleApp.ExpressionTree
{

    #region QueryExpression
    public class SelectExpression : Expression
    {
        public WhereExpression WhereExp { get; set; }
        public ColumnExpression ColumnExp { get; set; }
        public TakeExpression TakeExp { get; set; }
        public SkipExpression SkipExp { get; set; }
        public OrderExpression OrderExp { get; set; }
        public GroupExpression GroupExp { get; set; }
        public FromExpression FromExp { get; set; }
        public InnerJoinExpression InnerJoinExp { get; set; }
        public Expression Expression { get; set; }
        public int TotalRecord { get; set; }
        public int PageIndex { get; set; }
        public int PageSize { get; set; }
        public bool IsPage { get; set; }
        public bool IsHaveWhere
        {

            get
            {
                return this.WhereExp != null;
            }

        }
        public bool IsInnerJoin { get; set; }
        public SelectExpression(Expression expression)
        {
            this.Expression = expression;
            this.OrderExp = new OrderExpression();
            this.FromExp = new FromExpression();
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Select;
            }
        }
        public override Type Type
        {
            get
            {
                return this.ColumnExp.ReturnType;
            }
        }

    }
    public class InsertExpression : Expression
    {
        public object obj { get; set; }
        public Expression Expression { get; set; }
        public TableExpression Table { get; set; }
        public InsertExpression(object obj)
        {
            this.obj = obj;
            this.Expression = Expression.Constant(obj, obj.GetType());
            Table = new TableExpression(Expression.Constant(this.obj), "t0");
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Insert;
            }
        }
      
        public override Type Type
        {
            get
            {

                return typeof(int);
            }
        }
        
    }
    public class DeleteExpression : Expression
    {
        public object obj { get; set; }
        public Expression Expression { get; set; }
        public TableExpression Table { get; set; }
        public DeleteExpression(object obj, Expression expression)
        {
            this.obj = obj;
            this.Expression = expression;
            Table=new TableExpression(Expression.Constant(this.obj), "t0");
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Delete;
            }
        }
       
        public override Type Type
        {
            get
            {

                return typeof(int);
            }
        }
    }
    public class UpdateExpression : Expression
    {
        public Expression Expression { get; set; }
        public TableExpression Table { get; set; }
        public object obj { get; set; }
        public UpdateExpression(object obj, Expression expression)
        {
            
            this.obj = obj;
            this.Expression = expression;
            Table=new TableExpression(Expression.Constant(this.obj), "t0");
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Update;
            }
        }
       
        public override Type Type
        {
            get
            {

                return typeof(int);
            }
        }
    }



    public class WhereExpression : Expression
    {

        public Expression Expression { get; set; }

        public WhereExpression(Expression expression)
        {
            this.Expression = expression;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Where;
            }
        }


    }
    public class ColumnExpression : Expression
    {

        public Expression Expression { get; set; }
        public Type ReturnType { get; set; }
        public ColumnExpression(Expression expression)
        {
            
            if (expression.NodeType == ExpressionType.Quote) 
            {
                UnaryExpression ue=(UnaryExpression)expression;
                this.ReturnType = ((LambdaExpression)ue.Operand).ReturnType;
            }
            else if (expression.NodeType == ExpressionType.Call) 
            {
                this.ReturnType = typeof(int);
            }


            this.Expression = expression;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Column;
            }
        }

    }
    public class TakeExpression : Expression
    {

        public Expression Expression { get; set; }

        public TakeExpression(Expression expression)
        {
            this.Expression = expression;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Take;
            }
        }

    }
    public class SkipExpression : Expression
    {

        public Expression Expression { get; set; }

        public SkipExpression(Expression expression)
        {
            this.Expression = expression;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Skip;
            }
        }

    }
    public class OrderExpression : Expression
    {


        public List<Expression> OrderCollection { get; set; }
        public OrderExpression()
        {
            OrderCollection = new List<Expression>();
        }

        public void AddOrder(Expression expression)
        {
            this.OrderCollection.Add(expression);
        }
        public override ExpressionType NodeType
        {
            get
            {

                return (ExpressionType)QueryExpressionType.Order;
            }
        }

    }
    public class GroupExpression : Expression
    {

        public Expression Expression { get; set; }

        public GroupExpression(Expression expression)
        {
            this.Expression = expression;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.Group;
            }
        }

    }
    public class TableExpression : Expression
    {

        public Expression Expression { get; set; }
        public string Alias { get; set; }
        public string Name { get; set; }
        public string PrimaryKey { get; set; }
        public TableExpression(Expression expression, string name, string alias, string primaryKey) 
        {
            this.Expression = expression;
            this.Name = name;
            this.Alias = alias;
            this.PrimaryKey = primaryKey;
        }

        public TableExpression(Expression expression, string alias)
        {
            this.Expression = expression;
            this.Alias = alias;
            ConstantExpression ce = this.Expression as ConstantExpression;
            if (ce != null)
            {
                IQueryable q = ce.Value as IQueryable;
                if (q != null)
                {
                    var attributes = q.ElementType.GetCustomAttributes(typeof(TableMappingAttribute), true);

                    foreach (var attribute in attributes)
                    {
                        TableMappingAttribute a = attribute as TableMappingAttribute;
                        if (a != null)
                        {
                            this.Name = a.Name;
                            this.PrimaryKey = a.PrimaryKey;
                        }
                    }

                }
            }




        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.From;
            }
        }

    }
    public class FromExpression : Expression
    {

        public TableExpression Table { get; set; }
        public FromExpression()
        {
           
        }

        public void Add(Expression expression, string alias)
        {
            Table = new TableExpression(expression, alias);
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.From;
            }
        }

    }
    public class InnerJoinExpression : Expression
    {

        public Expression Expression { get; set; }
        public Expression InnerExp { get; set; }
        public Expression InnerKeyEx { get; set; }
        public Expression OutExp { get; set; }
        public Expression OutKeyExp { get; set; }
        public Expression ColumnExp { get; set; }
        public TableExpression InnerTable { get; set; }
        public InnerJoinExpression(Expression expression)
        {
            this.Expression = expression;
        }
        public InnerJoinExpression(Expression expression,TableExpression innerTable, Expression outExp, Expression innerExp, Expression innerKeyEx, Expression outKeyExp, Expression columnExp)
        {
            this.Expression = expression;
            this.InnerExp = innerExp;
            this.InnerKeyEx = innerKeyEx;
            this.OutExp = outExp;
            this.OutKeyExp = outKeyExp;
            this.ColumnExp = columnExp;
            this.InnerTable = innerTable;
        }
        public override ExpressionType NodeType
        {
            get
            {
                return (ExpressionType)QueryExpressionType.InnerJoin;
            }
        }

    }
    #endregion
}
